#
#   PyGUI - OpenGL Textures - Generic
#

from weakref import WeakKeyDictionary
from OpenGL.GL import glGenTextures, glBindTexture, glDeleteTextures
from GGLContexts import current_share_group
from GLDisplayLists import call_when_not_compiling_display_list

#----------------------------------------------------------------------

class TextureIdMap(WeakKeyDictionary):

    def __del__(self):
        #print "GL.TextureIdMap.__del__:", self ###
        def free_texture():
            glDeleteTextures([gl_id])
        for share_group, gl_id in self.items():
            context = share_group._some_member()
            if context:
                #print "...freeing texture id", gl_id, "for", share_group, "using", context ###
                context.with_context(free_texture)

#----------------------------------------------------------------------

class Texture(object):
    """This class encapsulates an OpenGL texture and maintains a
    representation of it for each OpenGL context with which it is used.
    Allocation and maintentance of texture numbers is handled automatically.
    
    Constructor:
        Texture(texture_type)
            where texture_type is the appropriate GL constant for the type
            of texture (GL_TEXTURE_2D etc.)
    """
    #
    #   _gl_type   int                 GL_TEXTURE_2D, etc.
    #   _gl_id     ShareGroup -> int   Mapping from OpenGL share group to texture number
    
    def __init__(self, texture_type):
        self._gl_type = texture_type
        self._gl_id = TextureIdMap()
    
    def deallocate(self):
        """Deallocate any OpenGL resources that have been allocated for this
        texture in any context."""
        self._gl_id.__del__()

    def bind(self):
        """Makes this texture the current texture for the current context
        by calling glBindTexture. If this texture has not previously been
        used with the current context, do_setup() is called to allocate
        and initialise a representation of the texture."""
        share_group = current_share_group()
        gl_id = self._gl_id.get(share_group)
        if gl_id is None:
            gl_id = glGenTextures(1)
            #print "GLTexture: assigned id %d for %s in share group %s" % (
            #    gl_id, self, share_group) ###
            self._gl_id[share_group] = gl_id
            call_when_not_compiling_display_list(lambda: self._setup(gl_id))
        glBindTexture(self._gl_type, gl_id)
    
    def _setup(self, gl_id):
        glBindTexture(self._gl_type, gl_id)
        self.do_setup()
    
    def do_setup(self):
        """Subclasses should override this to make the necessary OpenGL
        calls to initialise the texture, assuming that glBindTexture has
        already been called."""
        raise NotImplementedError
